
function parse(content) {

    var lastData;
    var id = 0;

    function parseSignleLine(content) {
        content = content.trim();

        // 忽略注释行。
        if (!content || content.charAt(0) == '/' || content.charAt(0) == '>') {
            return null;
        }

        // 处理标题行。
        if (content.charAt(0) == '#') {
            content = content.replace(/^#+\s*/, "");
            return {
                type: 'region',
                summary: content
            };
        }

        var fields = ['name', 'operandType', 'stackBehaviour', 'flowControl'];
        var ret = {type: 'item'};
        for (var i = 0; i < fields.length; i++) {
            var p = content.indexOf(' ');
            if (p <= 0) {
                ret[fields[i]] = content;
                content = '';
                break;
            }
            ret[fields[i]] = content.substr(0, p);
            content = content.substr(p + 1);
        }

        ret.rawSummary = ret.summary = content || '';

        ret.fieldName = ret.name.replace(/\./g, '_').replace(/^(switch|try|catch|throw|sizeof|typeof|volatile|break|lock)$/, "@$1");

        // 处理数据的合法性。
        if (ret.name.charAt(0) == '-') {
            lastData = ret;
            ret.isVirtual = true;
            ret.name = ret.name.substr(1);

            ret.summary = ret.summary.replace('~', '');

        } else {
            ret.isItem = true;
            ret.id = id++;
            ret.summary = ret.summary || lastData.rawSummary.replace('~', ({
                'i32': '（作为32位整数）',
                'i64': '（作为64位整数）',
                'u32': '（作为无符32位整数）',
                'u64': '（作为无符64位整数）',
                'f32': '（作为32位小数）',
                'f64': '（作为64位小数）',
            })[/[ifu]\d+$/.test(ret.name)]);

            for (var i = 1; i < fields.length; i++) {
                ret[fields[i]] = ret[fields[i]] || lastData[fields[i]];
            }

        }

        return ret;
    }

    content = content.split("\r\n");

    var ret = [];

    for (var i = 0; i < content.length; i++) {
        var data = parseSignleLine(content[i]);
        if (data) {
            if (data.type == 'region') {
                ret.push({
                    type: 'endRegion'
                });
            }
            ret.push(data);
        }
    }

    ret.push(ret.shift());

    console.log("count = " + id);

    return ret;

}

function generate(input, content) {

    function generateItems(data) {
        var ret = [];
        for (var i = 0; i < data.length; i++) {
            if (data[i].isItem) {
                ret.push('\r\n');
                ret.push('\t/// <summary>\r\n');
                ret.push('\t/// ' + data[i].summary + '\r\n');
                ret.push('\t/// </summary>\r\n');
                ret.push('\t' + data[i].fieldName + ' = ' + data[i].id + ',\r\n');
            } else if (data[i].type == 'region') {
                ret.push('\r\n');
                ret.push('\t#region ' + data[i].summary + '\r\n');
            } else if (data[i].type == 'endRegion') {
                ret.push('\r\n');
                ret.push('\t#endregion\r\n');
            }
        }
        ret = ret.join('');
        return ret;
    }

    function generateNames(data) {
        var ret = [];
        for (var i = 0; i < data.length; i++) {
            if (data[i].isItem) {
                ret.push('"' + data[i].name + '"');
            }
        }
        ret = ret.join(',\r\n\t\t');
        return ret;
    }

    function generateLists(data, typeName, fieldName) {
        var ret = [];
        for (var i = 0; i < data.length; i++) {
            if (data[i].isItem) {
                ret.push('\r\n');
                ret.push('\t\t// ' + data[i].name + '\r\n');
                ret.push('\t\t' + typeName + '.' + data[i][fieldName] + ', \r\n');
            }
        }
        ret = ret.join('');
        return ret;
    }

    var data = parse(content);

    return input.replace('//Header//', '// This file is generated by a tool. DO NOT EDIT!!!')
		.replace('//Items//', generateItems(data))
		.replace('//Names//', generateNames(data))
		.replace('//OperandTypes//', generateLists(data, "OperandType", "operandType"))
		.replace('//StackBehaviours//', generateLists(data, "StackBehaviour", "stackBehaviour"))
		.replace('//FlowControls//', generateLists(data, "FlowControl", "flowControl"));

}

function main() {
    var prefix = "OpCodeType";
    var fs = require('fs');
    var input = fs.readFileSync(prefix + '.src.txt', 'utf8');
    var content = fs.readFileSync(prefix + '.data.txt', 'utf8');

    var newContent = generate(input, content);
    fs.writeFileSync(prefix + '.cs', newContent, 'utf-8');

}
  
function generateSwitch() {
    var ret = [];
    var data = parse(content);
    for (var i = 0; i < data.length; i++) {
        if (data[i].isItem) {
            ret.push('\r\n');
            ret.push('case OpCodeTypeType.' + data[i].fieldName + ':\r\n');
            ret.push('\ttodo();\r\n');
            ret.push('\tbreek;\r\n');
        }
    }
    ret.push('\r\n');
    ret = ret.join('');
    fs.writeFileSync('OpCodeType.switch.txt', ret, 'utf-8');
}

function generateDoc() {

    var data = parse(content);

    var ret = [];

    for (var i = 0; i < data.length; i++) {
        if (data[i].type == 'region') {
            ret.push('\r\n## ' + data[i].summary + '\r\n\r\n');
        } else if (data[i].type == 'item') {
            ret.push('\r\n### ' + data[i].name);
            if (!data[i].isVirtual) { ret.push(' <sub>(id=' + data[i].id + ')</sub>'); }

            ret.push('\r\n');
            ret.push(data[i].summary);

            ret.push('\r\n\r\n#### 用法:\r\n\r\n');
            ret.push('\t' + data[i].name + ' ');

            switch (data[i].operandType) {
                case 'none':
                    break;
                case 'label':
                    ret.push('*label(32b)*')
                    break;
                case 'labels':
                    ret.push('*label(8b)*')
                    break;
                case 'method':
                    ret.push('*method(32b)*')
                    break;
                case '@const':
                    ret.push('*natural type* *natural constant*')
                    break;
                case 'type':
                    ret.push('*type(32b)*')
                    break;
                case 'field':
                    ret.push('*field(32b)*')
                    break;
                case 'i8':
                    ret.push('*int(8b)*')
                    break;
                case 'i16':
                    ret.push('*int(16b)*')
                    break;
                case 'i32':
                    ret.push('*int(32b)*')
                    break;
                case 'i64':
                    ret.push('*int(64b)*')
                    break;
                case 'f32':
                    ret.push('*float(32b)*')
                    break;
                case 'f64':
                    ret.push('*float(64b)*')
                    break;
                case 'caselist':
                    ret.push('*constant1* *label1* ...')
                    break;
                default:
                    ret.push('<args>');
            }

            ret.push('\r\n\r\n');

        }
    }
    ret.push('\r\n');
    ret = ret.join('');

    fs.writeFileSync('OpCodeType.md.txt', ret, 'utf-8');

}

//generateDoc();

// F:\web\jplusui\_node\node\node OpCodeType.gen.js
// F:\window\Tea\TeaCompiler\ByteCode\Common
// F:\\window\\Tea\\TeaCompiler\\ByteCode\\Common\\
main();




